Skip to content

18.2 Financial Data Analyst:智能财务数据分析师

项目定位:一个交互式财务数据分析应用,融合 Claude AI 的智能分析能力与 Recharts 可视化功能,支持多格式文件上传、趋势识别和动态图表生成。


1. 项目概述

1.1 核心功能

Financial Data Analyst 是一个基于 Next.js 的高级数据分析应用:

功能描述
智能数据分析Claude 3 Haiku / Sonnet 驱动的数据解析和趋势识别
多格式支持PDF、CSV、TXT、MD、图片等多种文件格式
交互式可视化6 种图表类型,支持动态生成和定制
对话式交互通过自然语言请求特定分析和可视化
文件预览上传后可预览文件内容

1.2 支持的图表类型

┌─────────────────────────────────────────────────────────────────┐
│                     支持的可视化类型                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  📈 折线图 (Line Chart)        📊 柱状图 (Bar Chart)            │
│     时间序列、趋势分析              单指标对比                    │
│                                                                  │
│  📊 多柱状图 (Multi Bar)        📉 面积图 (Area Chart)          │
│     多指标对比                      数量随时间变化               │
│                                                                  │
│  📊 堆叠面积图 (Stacked)        🥧 饼图 (Pie Chart)             │
│     成分分解                        比例分布                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

1.3 技术栈

前端框架:     Next.js 14 + React
编程语言:     TypeScript
样式方案:     TailwindCSS
UI 组件库:    shadcn/ui
数据可视化:   Recharts
PDF 处理:     PDF.js
AI 引擎:      Anthropic Claude API
运行时:       Edge Runtime

2. 项目结构解析

2.1 目录结构

financial-data-analyst/
├── app/                      # Next.js 应用目录
│   ├── api/
│   │   └── chat/
│   │       └── route.ts     # 聊天 API(Edge Runtime)
│   ├── page.tsx             # 主页面
│   └── layout.tsx           # 布局
├── components/               # React 组件
│   ├── ui/                  # shadcn/ui 组件
│   ├── ChatArea.tsx         # 聊天区域
│   ├── FileUpload.tsx       # 文件上传
│   ├── ChartRenderer.tsx    # 图表渲染器
│   └── MessageBubble.tsx    # 消息气泡
├── hooks/                    # 自定义 Hooks
│   ├── useChat.ts           # 聊天逻辑
│   └── useFileUpload.ts     # 文件上传逻辑
├── lib/                      # 工具库
│   ├── anthropic.ts         # Claude API 客户端
│   └── chartUtils.ts        # 图表工具函数
├── types/                    # TypeScript 类型定义
│   ├── chat.ts              # 聊天相关类型
│   └── chart.ts             # 图表相关类型
├── utils/                    # 实用函数
│   ├── fileParser.ts        # 文件解析
│   └── dataTransform.ts     # 数据转换
├── tailwind.config.ts
├── tsconfig.json
└── package.json

2.2 数据流架构

用户操作

    ├─── 上传文件 ───────────────────────┐
    │                                    │
    │                                    ▼
    │                        ┌─────────────────────┐
    │                        │   文件解析器        │
    │                        │   (PDF.js / CSV)    │
    │                        └─────────────────────┘
    │                                    │
    │                                    ▼
    │                        ┌─────────────────────┐
    │                        │   提取文本/数据     │
    │                        └─────────────────────┘
    │                                    │
    └─── 输入问题 ───────────────────────┤


                            ┌─────────────────────┐
                            │    Claude API       │
                            │   (分析 + 可视化)   │
                            └─────────────────────┘


                            ┌─────────────────────┐
                            │   解析 AI 响应      │
                            │   (文本 + 图表配置) │
                            └─────────────────────┘

              ┌──────────────────────────┼──────────────────────────┐
              │                          │                          │
              ▼                          ▼                          ▼
     ┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
     │   文本回复      │      │   图表渲染      │      │   数据表格      │
     │   (Markdown)    │      │   (Recharts)    │      │   (可选)        │
     └─────────────────┘      └─────────────────┘      └─────────────────┘

3. 核心实现详解

3.1 文件解析系统

支持多种文件格式的解析:

typescript
// utils/fileParser.ts

import * as pdfjsLib from 'pdfjs-dist';

export async function parseFile(file: File): Promise<string> {
  const extension = file.name.split('.').pop()?.toLowerCase();

  switch (extension) {
    case 'pdf':
      return parsePDF(file);
    case 'csv':
      return parseCSV(file);
    case 'txt':
    case 'md':
    case 'html':
      return parseText(file);
    default:
      throw new Error(`Unsupported file type: ${extension}`);
  }
}

async function parsePDF(file: File): Promise<string> {
  const arrayBuffer = await file.arrayBuffer();
  const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;

  let fullText = '';
  for (let i = 1; i <= pdf.numPages; i++) {
    const page = await pdf.getPage(i);
    const textContent = await page.getTextContent();
    const pageText = textContent.items
      .map((item: any) => item.str)
      .join(' ');
    fullText += pageText + '\n';
  }

  return fullText;
}

async function parseCSV(file: File): Promise<string> {
  const text = await file.text();
  // 返回原始 CSV 文本,让 Claude 解析
  return text;
}

3.2 Claude API 调用

使用 Edge Runtime 实现流式响应:

typescript
// app/api/chat/route.ts

import Anthropic from '@anthropic-ai/sdk';

export const runtime = 'edge';

const anthropic = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

export async function POST(request: Request) {
  const { messages, fileContent } = await request.json();

  // 构建系统提示
  const systemPrompt = `
你是一位专业的财务数据分析师。你的任务是:
1. 分析用户提供的财务数据
2. 识别趋势、模式和异常
3. 根据用户请求生成可视化图表

当需要生成图表时,使用以下 JSON 格式:
\`\`\`chart
{
  "type": "line" | "bar" | "multi-bar" | "area" | "stacked-area" | "pie",
  "title": "图表标题",
  "data": [
    { "name": "标签1", "value": 100 },
    { "name": "标签2", "value": 200 }
  ],
  "xAxisKey": "name",
  "yAxisKeys": ["value"],
  "colors": ["#3b82f6", "#10b981"]
}
\`\`\`

${fileContent ? `以下是用户上传的文件内容:\n${fileContent}` : ''}
`;

  const response = await anthropic.messages.create({
    model: 'claude-3-5-sonnet-20240620',
    max_tokens: 4096,
    system: systemPrompt,
    messages: messages.map((m: any) => ({
      role: m.role,
      content: m.content,
    })),
    stream: true,
  });

  // 返回流式响应
  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      for await (const event of response) {
        if (event.type === 'content_block_delta') {
          const text = event.delta.text;
          controller.enqueue(encoder.encode(text));
        }
      }
      controller.close();
    },
  });

  return new Response(stream, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  });
}

3.3 图表渲染器

从 AI 响应中提取并渲染图表:

typescript
// components/ChartRenderer.tsx

import {
  LineChart, Line, BarChart, Bar, AreaChart, Area,
  PieChart, Pie, XAxis, YAxis, Tooltip, Legend,
  ResponsiveContainer, Cell,
} from 'recharts';

interface ChartConfig {
  type: 'line' | 'bar' | 'multi-bar' | 'area' | 'stacked-area' | 'pie';
  title: string;
  data: any[];
  xAxisKey: string;
  yAxisKeys: string[];
  colors: string[];
}

export function ChartRenderer({ config }: { config: ChartConfig }) {
  const { type, title, data, xAxisKey, yAxisKeys, colors } = config;

  const renderChart = () => {
    switch (type) {
      case 'line':
        return (
          <LineChart data={data}>
            <XAxis dataKey={xAxisKey} />
            <YAxis />
            <Tooltip />
            <Legend />
            {yAxisKeys.map((key, index) => (
              <Line
                key={key}
                type="monotone"
                dataKey={key}
                stroke={colors[index % colors.length]}
                strokeWidth={2}
              />
            ))}
          </LineChart>
        );

      case 'bar':
        return (
          <BarChart data={data}>
            <XAxis dataKey={xAxisKey} />
            <YAxis />
            <Tooltip />
            <Legend />
            {yAxisKeys.map((key, index) => (
              <Bar
                key={key}
                dataKey={key}
                fill={colors[index % colors.length]}
              />
            ))}
          </BarChart>
        );

      case 'pie':
        return (
          <PieChart>
            <Pie
              data={data}
              dataKey="value"
              nameKey="name"
              cx="50%"
              cy="50%"
              outerRadius={80}
              label
            >
              {data.map((_, index) => (
                <Cell key={index} fill={colors[index % colors.length]} />
              ))}
            </Pie>
            <Tooltip />
            <Legend />
          </PieChart>
        );

      // ... 其他图表类型
    }
  };

  return (
    <div className="w-full h-80 my-4">
      <h3 className="text-lg font-semibold mb-2">{title}</h3>
      <ResponsiveContainer width="100%" height="100%">
        {renderChart()}
      </ResponsiveContainer>
    </div>
  );
}

3.4 消息解析与渲染

解析 AI 响应中的文本和图表配置:

typescript
// utils/messageParser.ts

interface ParsedContent {
  type: 'text' | 'chart';
  content: string | ChartConfig;
}

export function parseAIResponse(response: string): ParsedContent[] {
  const parts: ParsedContent[] = [];
  const chartRegex = /```chart\n([\s\S]*?)\n```/g;

  let lastIndex = 0;
  let match;

  while ((match = chartRegex.exec(response)) !== null) {
    // 添加图表前的文本
    if (match.index > lastIndex) {
      const text = response.slice(lastIndex, match.index).trim();
      if (text) {
        parts.push({ type: 'text', content: text });
      }
    }

    // 解析图表配置
    try {
      const chartConfig = JSON.parse(match[1]);
      parts.push({ type: 'chart', content: chartConfig });
    } catch (e) {
      console.error('Failed to parse chart config:', e);
    }

    lastIndex = match.index + match[0].length;
  }

  // 添加剩余文本
  if (lastIndex < response.length) {
    const text = response.slice(lastIndex).trim();
    if (text) {
      parts.push({ type: 'text', content: text });
    }
  }

  return parts;
}

4. 使用场景

4.1 主要用途

数据提取与分析

用户: 请分析这份财务报表中的营收趋势

Claude:
根据您上传的财务报表,以下是关键发现:

1. **营收增长**:2024年Q1-Q4营收呈持续增长态势
   - Q1: $1.2M → Q4: $2.1M(增长75%)

2. **季节性特征**:Q4销售明显高于其他季度

3. **建议**:建议关注Q2的增长放缓原因

[生成营收趋势折线图]

可视化创建

用户: 帮我用饼图展示各部门支出占比

Claude:
根据您的数据,各部门支出分布如下:

- 研发部门: 35%
- 销售部门: 28%
- 运营部门: 22%
- 行政部门: 15%

[生成支出占比饼图]

4.2 创意扩展应用

这个项目的架构可以轻松扩展到其他领域:

应用场景数据类型可视化重点
环保数据分析碳排放、能源消耗趋势图、对比图
体育数据追踪运动员表现、比赛统计雷达图、柱状图
社交媒体分析粉丝增长、互动率面积图、饼图
教育进度追踪成绩、出勤率折线图、堆叠图
健康数据监测运动量、睡眠质量趋势图、对比图

5. 本地运行

5.1 环境要求

  • Node.js 18+
  • Anthropic API Key

5.2 安装与运行

bash
# 克隆仓库
git clone https://github.com/anthropics/claude-quickstarts.git
cd claude-quickstarts/financial-data-analyst

# 安装依赖
npm install

# 配置环境变量
echo "ANTHROPIC_API_KEY=your_api_key" > .env.local

# 启动开发服务器
npm run dev

访问 http://localhost:3000 即可使用。

5.3 常见问题

问题解决方案
PDF 解析失败确保 PDF 是文本型(非扫描件)
图表不显示检查 AI 响应格式是否正确
API 调用失败验证 API Key 是否有效
文件过大分割文件或只上传关键部分

6. 架构亮点

6.1 设计决策

决策理由
Edge Runtime更快的冷启动,适合流式响应
RechartsReact 生态最流行的图表库,易于定制
JSON 图表配置让 Claude 生成结构化数据,便于渲染
流式响应提升用户体验,实时显示分析过程

6.2 性能优化

typescript
// 1. 使用 React.lazy 懒加载图表组件
const ChartRenderer = React.lazy(() => import('./ChartRenderer'));

// 2. 使用 useMemo 缓存解析结果
const parsedContent = useMemo(
  () => parseAIResponse(message.content),
  [message.content]
);

// 3. 文件分块上传
async function uploadLargeFile(file: File, chunkSize = 1024 * 1024) {
  const chunks = Math.ceil(file.size / chunkSize);
  // ... 分块处理
}

6.3 扩展性设计

typescript
// 添加新的图表类型只需:
// 1. 在 ChartConfig 中添加类型
type ChartType = 'line' | 'bar' | 'radar'; // 添加 'radar'

// 2. 在 renderChart 中添加渲染逻辑
case 'radar':
  return <RadarChart data={data}>...</RadarChart>;

// 3. 更新系统提示告知 Claude

7. 与其他方案的对比

7.1 vs 传统 BI 工具(Tableau、Power BI)

特性Financial Data Analyst传统 BI
学习成本低(自然语言交互)高(需学习工具)
灵活性高(任意问题)中(预设报表)
数据连接文件上传多种数据源
协作能力基础强大
成本按 API 调用付费订阅制

7.2 vs 纯代码方案(Python + Matplotlib)

特性Financial Data AnalystPython 方案
开发效率高(对话即可视化)中(需编码)
定制性
交互体验好(Web UI)一般(静态图)
复杂分析依赖 Claude完全控制

8. 总结

Financial Data Analyst 展示了 AI 驱动的数据分析新范式:

方面评价
创新性⭐⭐⭐⭐⭐ 对话式数据分析
实用性⭐⭐⭐⭐ 支持主流文件格式和图表
代码质量⭐⭐⭐⭐ TypeScript + 模块化设计
部署难度⭐⭐ 只需 API Key

适用场景

  • 快速探索性数据分析
  • 非技术人员的数据可视化需求
  • 财务报告的自动化解读
  • 学习 AI + 可视化集成

学习要点

  • Next.js Edge Runtime 的使用
  • 流式响应的实现
  • AI 响应中嵌入结构化数据
  • Recharts 动态图表渲染

下一节,我们将深入学习 Computer Use Demo,探索 Claude 独有的桌面控制能力。

基于 MIT 许可证发布。内容版权归作者所有。